package cn.bon.common.interceptor;

import cn.bon.common.exception.DbException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.defaults.RawSqlSource;
import org.springframework.beans.factory.annotation.Value;

import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author Lc_cL
 * @Date 2023/12/26
 * @Description 查询时自动筛选 逻辑删除
 */
@Slf4j
@Intercepts({
        @Signature(
                type = Executor.class,
                method = "query",
                args = {
                        MappedStatement.class,
                        Object.class,
                        org.apache.ibatis.session.RowBounds.class,
                        org.apache.ibatis.session.ResultHandler.class
                }
        )
})
public class MybatisSelectInterceptor implements Interceptor {
    @Value("${bon.mybatis.logic-not-delete-value}")
    private String logicNotDeleteValue;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("MybatisSelectInterceptor run...");
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];

        // 获取SQL的命令类型
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();

        // 获取参数对象
        Object parameter = args[1];

        if (sqlCommandType == SqlCommandType.SELECT) {
            handlerSelete(mappedStatement, parameter);
        }

        // 执行原有的查询逻辑
        return invocation.proceed();
    }

    private void handlerSelete(MappedStatement mappedStatement, Object parameter) {
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        String originSql = boundSql.getSql();
        if (originSql.contains("del_flag=")) return ;

        String modifiedSql = remodifySQL(originSql);
        modifyMappedStatement(mappedStatement,modifiedSql);
    }

    /**
     * 反射 修改MappedStatement
     * @param mappedStatement
     * @param sql
     */
    private void modifyMappedStatement(MappedStatement mappedStatement, String sql) {
        try {
            //暴力反射，修改sql
            Field rawSqlSourceField = mappedStatement.getClass().getDeclaredField("sqlSource");
            rawSqlSourceField.setAccessible(true);
            SqlSource rawSqlSource = (RawSqlSource) rawSqlSourceField.get(mappedStatement);


            Field staticSqlSourceFiled = rawSqlSource.getClass().getDeclaredField("sqlSource");
            staticSqlSourceFiled.setAccessible(true);
            SqlSource staticSqlSource = (StaticSqlSource) staticSqlSourceFiled.get(rawSqlSource);


            Field sqlField = staticSqlSource.getClass().getDeclaredField("sql");
            sqlField.setAccessible(true);

            sqlField.set(staticSqlSource, sql);
            staticSqlSourceFiled.set(rawSqlSource, staticSqlSource);
            rawSqlSourceField.set(mappedStatement, rawSqlSource);

            sqlField.setAccessible(false);
            staticSqlSourceFiled.setAccessible(false);
            rawSqlSourceField.setAccessible(false);

        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new DbException("查询 反射注入逻辑删除失败");
        }
    }

    /**
     * 修改SQL语句
     * @param originSQL
     * @return
     */
    private String remodifySQL(String originSQL) {
        if (logicNotDeleteValue == null) {
            log.warn("未配置逻辑删除，默认使用 0(String)");
            logicNotDeleteValue = "0";
        }

        if (originSQL.contains("WHERE") || originSQL.contains("where")) {
            originSQL = originSQL.replace("WHERE", "WHERE del_flag=" + logicNotDeleteValue + " AND");
            originSQL = originSQL.replace("where", "WHERE del_flag=" + logicNotDeleteValue + " AND");
            return originSQL;
        }

        // 正则表达式匹配 GROUP BY、HAVING、ORDER BY 和 LIMIT 子句
        Pattern pattern = Pattern.compile("\\b(GROUP BY|HAVING|ORDER BY|LIMIT)\\b", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(originSQL);

        // 查找 子句的位置
        int whereIndex = -1;

        // 寻找最后一个匹配项，以确保它是在 ORDER BY 或 LIMIT 之前
        while (matcher.find() && whereIndex == -1) {
            whereIndex = matcher.start();
        }

        // 在 WHERE 子句中添加 del_flag=0
        if (whereIndex != -1) {
            originSQL = originSQL.substring(0, whereIndex) + "WHERE del_flag=" + logicNotDeleteValue + originSQL.substring(whereIndex);
        }
        return originSQL;
    }
}